package it.ap.sa.core.configuration.reader;

import java.util.Map;
import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import it.ap.sa.core.configuration.commons.IConfiguration;
import it.ap.sa.core.configuration.service.ConfigurationService;
import it.ap.sa.core.utils.CoreProperties;

/**
 * @author Alessandro Paolillo
 */
@Component
public class ConfigurationFilePropertyReader implements IConfigurationReader {
	
	public static final Logger logger = LoggerFactory.getLogger(ConfigurationFilePropertyReader.class.getName());

	@Autowired
	private CoreProperties property;

	/**
	 * Legge i parametri di configurazione usando il reader su file e l' inserisce nell'oggetto {@link IConfiguration}
	 * di modo da renderli disponibili sempre in qualsiasi punto dell'applicazione.
	 * Se non valorizzata la proprietà "configurationFile" in config.properties, il reader su file leggerà come parametri di
	 * configurazione quelli del file di properties "config.properties".
	 * 
	 * @param {@link Map<String,String>} otherParams, parametri in più da voler aggiungere al configuration.
	 * 
	 * @return {@link IConfiguration}
	 */
	@Override
	public IConfiguration readConfiguration(Map<String, String> otherParams) {
		try{
			/** **/
			if (!StringUtils.hasText(property.configurationFile) && !StringUtils.hasText(property.defaultConfigurationFile)) {
				logger.error(">>>>>>>>>>>>>>>> Non è stato trovato ne il config.properties ne altro file di properties da cui il reader possa leggere i parametri. <<<<<<<<<<<<<<<");
				
				throw new RuntimeException("Nessun file di properties trovato dal reader.");
			}
			
			/*
		     * Creates an empty property list with no default values.
		     */
			Properties properties = new Properties();
			/*
			 * Create a new DefaultResourceLoader.
			 * <p>ClassLoader access will happen using the thread context class loader
			 * at the time of this ResourceLoader's initialization.
			 * @see java.lang.Thread#getContextClassLoader()
			 */
			DefaultResourceLoader loader = new DefaultResourceLoader();
			
			
			/* per default il file config.properties è quello da cui leggere i parametri **/
			String fileRead = property.defaultConfigurationFile;
			
			logger.info("Il reader leggerà i parametri dal seguente file di deafult : " + fileRead);
			
			/* Carico le properties dal file di deafult **/
			Resource resource = loader.getResource(fileRead);
			
			/*
		     * load property list from file.
		     */
			properties.load(resource.getInputStream());
			
			/*
			 * Ciclo la lista di proprieta' lette e le aggiungo all'oggetto {@link IConfiguration}.
			 */
			properties.forEach((k,v)->{
				ConfigurationService.getConfig().setProperty(k.toString(), v);
			});

			logger.info("Terminata la lettura dei parametri del file di deafult : " + fileRead);
			
			/* 
			 * Controllo se è stato indicato un ulteriore file di configurazione custom 
			 */
			if (StringUtils.hasText(property.configurationFile)) {
				/* get custom file */
				fileRead = property.configurationFile;
			
				logger.info("Il reader leggerà i parametri dal seguente file custom: " + fileRead);
		
				/* Creates an empty property list with no default values.  */
				properties = new Properties();
				
				/* Create a new DefaultResourceLoader. */
				loader = new DefaultResourceLoader();
			
				/* load resource properties **/
				resource = loader.getResource(fileRead);
				
				/* Controllo che il file esiste, sia accessibile, ecc ... **/
				if (resource.getFile() == null || !resource.getFile().exists() || !resource.getFile().isFile() || !resource.getFile().canRead()) {
					logger.error("Verificare la correttezza del file indicato per il reader. Possibile cause dell'errore: ");
						logger.error(" - è null? : " + resource.getFile());
						
						if(resource.getFile() != null){
							logger.error(" - esiste? : " + resource.getFile().exists());
							logger.error(" - è un file? : " + resource.getFile().isFile());
							logger.error(" - accessibile in lettura? : " + resource.getFile().canRead());
						}
					
					throw new RuntimeException("Errore durante la lettura da file dei parametri di configurazione dell'applicazione.");
				}

				/* load property list from file. */
				properties.load(resource.getInputStream());
				
				/*
				 * Ciclo la lista di proprieta' lette e le aggiungo all'oggetto {@link IConfiguration}.
				 */
				properties.forEach((k,v)->{
					ConfigurationService.getConfig().setProperty(k.toString(), v);
				});
				
				logger.info("Terminata la lettura dei parametri del file custom : " + fileRead);
			}// close read file custom
			
			
			/*
			 * Controllo se ci sono parametri aggiunti da aggiungere al configuration passati dalla mappa che
			 * il servizio prende in ingresso.
			 */
			if(otherParams != null && !otherParams.isEmpty()){
				/*
				 * Ciclo la lista di proprieta' della mappa aggiuntiva e le aggiungo all'oggetto {@link IConfiguration}.
				 */
				otherParams.forEach((k,v)->{
					ConfigurationService.getConfig().setProperty(k, v);
				});
			}
			
			return ConfigurationService.getConfig();
		}catch(Exception e){
			logger.error("Errore durante la lettura dei parametri di configurazione dell'applicazione " + e, e);
			
			throw new RuntimeException("Errore durante la lettura da file dei parametri di configurazione dell'applicazione.");
		}
	}
}
